package com.leapcloud.crm.core.utils;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;

/**
 * json处理类
 *
 * @author wangzhenyan
 */
public class JsonUtils {
  private final static Logger LOGGER = LoggerFactory.getLogger(JsonUtils.class);

  private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
  public static final ObjectMapper mapper;
  public static final ObjectMapper prettyMapper;

  static {
    mapper = new ObjectMapper();
    mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);

    prettyMapper = new ObjectMapper();
    prettyMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
    prettyMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
  }


  public static ObjectMapper getMapper() {
    return mapper;
  }

  public static String encode(Object obj) {
    try {
      if (StringUtils.isEmpty(obj)) return null;
      //强制将Date类型转化为时间戳
      SimpleModule module = new SimpleModule();
      module.addSerializer(Date.class, new JsonDateForLongSerializer());
      mapper.registerModule(module);
      return mapper.writeValueAsString(obj);
    } catch (Exception e) {
      LOGGER.error("转换json字符失败!obj={}, error={}", obj, e.getMessage());
    }
    return null;
  }

  public static String encode(Object obj, String defaultValue) {
    String result = encode(obj);
    if (StringUtils.isEmpty(result)) {
      return defaultValue;
    }
    return result;
  }


  /**
   * jackson 解析成对象,json中属性必须与对象中的变量一致
   *
   * @param json
   * @param classze
   * @param <T>
   * @return
   */
  public static <T> T decode(String json, Class<T> classze) {
    try {
      if (StringUtils.isEmpty(json)) {
        return null;
      }
      return mapper.readValue(json, classze);
    } catch (Exception e) {
      LOGGER.error("json转换对象失败! json={}, error={}", json, e.getMessage());

    }
    return null;
  }

  public static <T> T decode(String json, JavaType javaType) {
    try {
      if (StringUtils.isEmpty(json)) {
        return null;
      }
      return mapper.readValue(json, javaType);
    } catch (Exception e) {
      LOGGER.error("json转换对象失败! json={}, error={}", json, e.getMessage());

    }
    return null;
  }

  public static <T> T decode(Object obj, Class<T> classze) {
    try {
      if (obj == null) {
        return null;
      }
      return mapper.readValue(JsonUtils.encode(obj), classze);
    } catch (Exception e) {
      LOGGER.error("obj转换obj失败! json={}, error={}", obj, e.getMessage());
    }
    return null;
  }

  public static <T extends Collection, D> T decode(String json, Class<T> class1, Class<D> class2) {
    try {
      if (StringUtils.isEmpty(json)) {
        return null;
      }
      JavaType type = JsonUtils.getMapper().getTypeFactory().constructCollectionType(class1, class2);
      return decode(json, type);
    } catch (Exception e) {
      LOGGER.error("json转换对象失败! json={}, error={}", json, e.getMessage());
      return null;
    }
  }

  public static <T, D extends Collection, M> T decode(String json, Class<T> class1, Class<D> class2, Class<M> class3) {
    try {
      if (StringUtils.isEmpty(json)) {
        return null;
      }
      JavaType type1 = JsonUtils.getMapper().getTypeFactory().constructCollectionType(class2, class3);

      JavaType type = JsonUtils.getMapper().getTypeFactory().constructReferenceType(class1, type1);
      return decode(json, type);
    } catch (Exception e) {
      LOGGER.error("json转换对象失败! json={}, error={}", json, e.getMessage());
      return null;
    }
  }

  public static <T> T decodeForDate(String json, Class<T> classze) {
    try {
      if (StringUtils.isEmpty(json)) {
        return null;
      }
      mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
      return mapper.readValue(json, classze);
    } catch (Exception e) {
      LOGGER.error("json转换对象失败! json={}, error={}", json, e.getMessage());

    }
    return null;
  }

  public <T> T toObject(String json, Class<T> clazz) {
    try {
      if (StringUtils.isEmpty(json)) {
        return null;
      }
      return mapper.readValue(json, clazz);
    } catch (IOException e) {
      LOGGER.error("将json字符转换为对象时失败! json={}, error={}", json, e.getMessage());

    }
    return null;
  }

  /**
   * 转化指定格式的Date
   */
  public static class JsonDateSerializer extends JsonSerializer<Date> {
    private SimpleDateFormat dateFormat;

    public JsonDateSerializer(String format) {
      dateFormat = new SimpleDateFormat(format);
    }

    @Override
    public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
        throws IOException {
      String value = dateFormat.format(date);
      gen.writeString(value);
    }
  }


  // 反序列化对日期字符串解析为Date
  public static class JsonDateDeserializer extends JsonDeserializer<Date> {

    @Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext){
      SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
      try {
        String date = jsonParser.getText();
        if (StringUtils.isEmpty(date)) {
          return null;
        }
        return format.parse(date);
      } catch (Exception e) {
        LOGGER.error("解析日期失败", e);
        throw new RuntimeException(e);
      }
    }
  }

  public static class JsonDateForLongSerializer extends JsonSerializer<Date> {

    public JsonDateForLongSerializer() {
    }

    @Override
    public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
        throws IOException {
      Timestamp t = new Timestamp(date.getTime());
      gen.writeNumber(t.getTime());
    }
  }



  public static String encodePrettily(Object data) {
    String prettyJsonString = null;
    if (!StringUtils.isEmpty(data)) {
      try {
        prettyJsonString = prettyMapper.writeValueAsString(data);
      } catch (Exception e) {
        LOGGER.error("data--->formateJson failed, data={}", encode(data));
        return null;
      }
    }
    return prettyJsonString;
  }

  public static String encodePrettily(Object data, String dateformat) {
    String prettyJsonString = null;
    if (!StringUtils.isEmpty(data)) {
      try {
        mapper.setDateFormat(new SimpleDateFormat(dateformat));
        prettyJsonString = prettyMapper.writeValueAsString(data);
      } catch (Exception e) {
        LOGGER.error("data--->formateJson failed, data={}", encode(data));
        return null;
      }
    }
    return prettyJsonString;
  }

}